package ue;

import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;

import javax.swing.ImageIcon;

import packets.Packet;
import packets.PacketPDCCH;
import packets.PacketPDSCH;
import packets.RadioPacket;
import radiowaves.RadioWaves;
import utils.Duration;
import utils.Horloge;
import eNodeB.ENodeB;

public class UE extends Observable implements Runnable, Observer {
	private final int id;
	private static int nbUE;
	private double positionX;
	private double positionY;
	private final RadioWaves radio;
	/**
	 * idRB; value
	 */
	private final Map<Integer, Integer> mapCQI = new HashMap<Integer, Integer>();
	/**
	 * idRB; value
	 */
	private final Map<Integer, Double> mapThroughput = new HashMap<Integer, Double>();
	/**
	 * idUE; Map<idRB,average>
	 */
	private static final Map<String, Map<Integer, Double>> mapAverageThroughput = new HashMap<String, Map<Integer, Double>>();
	/**
	 * idUE; Map<idRB,numberofDemand>
	 */
	private static final Map<String, Map<Integer, Integer>> nbThroughputDemand = new HashMap<String, Map<Integer, Integer>>();
	private final String MACAddress;
	private final Duration duration;
	private final ImageIcon img;
	private Color color;

	public Map<String, Map<Integer, Double>> getMapAverageThroughput() {
		return mapAverageThroughput;
	}

	public UE(double positionX, double positionY, String mac, ENodeB eNodeB,
			RadioWaves rw, Duration duration) {
		this.img = new ImageIcon(this.getClass().getResource("/Images/ue.png"));
		this.duration = duration;
		radio = rw;
		addObserver(eNodeB);
		eNodeB.getHorloge().addObserver(this);
		this.positionX = positionX;
		this.positionY = positionY;
		MACAddress = mac;
		id = nbUE++;

	}

	/**
	 * @return the positionX
	 */
	public synchronized double getPositionX() {
		return positionX;
	}

	/**
	 * @param positionX
	 *            the positionX to set
	 */
	public void setPositionXY(double positionX, double positionY) {
		this.positionX = positionX;
		this.positionY = positionY;
		setChanged();
		notifyObservers("UEMove");
	}

	/**
	 * @return the positionY
	 */
	public synchronized double getPositionY() {
		return positionY;

	}

	public ImageIcon getImage() {
		return img;
	}

	public Map<String, Map<Integer, Integer>> getMapThroughputDemand() {
		return nbThroughputDemand;
	}

	public double getAverageThroughput(String idUEMAC, int idRB) {
		Map<Integer, Integer> nbDemandmap = nbThroughputDemand.get(idUEMAC);
		if (nbDemandmap == null) {
			nbDemandmap = new HashMap<Integer, Integer>();
		}
		Integer nb = nbDemandmap.get(idRB);
		if (nb == null) {
			nbDemandmap.put(idRB, 0);
			nbThroughputDemand.put(idUEMAC, nbDemandmap);
		}

		Map<Integer, Double> average = mapAverageThroughput.get(idUEMAC);
		if (average == null) {
			average = new HashMap<Integer, Double>();

		}
		Double theAverage = average.get(idRB);
		if (theAverage == null) {
			average.put(idRB, 0.0);
			mapAverageThroughput.put(idUEMAC, average);
		}
		theAverage = average.get(idRB);

		return theAverage;

	}

	public void setColor(int r, int g, int b) {
		color = new Color(r, g, b);
	}

	public synchronized double getThroughPut(int id) {

		return mapThroughput.get(id);

	}

	public synchronized String getMAC() {
		return MACAddress;
	}

	public Color getColor() {
		return color;
	}

	public int getId() {
		return id;
	}

	public synchronized List<RadioPacket> listenForPackets() {
		List<RadioPacket> packets = new ArrayList<RadioPacket>();
		try {
			radio.getSem().acquire();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		packets = this.radio.searchForPackets(this.MACAddress);
		radio.getSem().release();
		return packets;
	}

	@Override
	public void run() {
		while (true) {

			List<RadioPacket> radiopackets = listenForPackets();

			for (RadioPacket rp : radiopackets) {
				try {
					radio.getSem().acquire();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				radio.removePacket(rp);
				radio.getSem().release();
				Packet p = rp.getPayload();
				if (p instanceof PacketPDCCH) {
					// PacketPDCCH pkt = (PacketPDCCH) p;
					// System.out.println("UE" + getId() + " received RBs : "
					// + pkt.getRBs());
				} else if (p instanceof PacketPDSCH) {
					// PacketPDSCH pkt = (PacketPDSCH) p;
					// System.out.println("UE" + getId() + " received data : "
					// + pkt.getData().getData());
				} else {
					// System.out.println("Unrecognized packet for UE" +
					// getId());
				}
			}
		}
	}

	public void addCqi(int rbId, int cqi) {
		mapCQI.put(rbId, cqi);
	}

	public void addThroughput(int rbId, double throughput) {

		mapThroughput.put(rbId, throughput);
	}

	public int getCQI(int rbId) {
		return mapCQI.get(rbId);
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer("UE");
		sb.append(id + 1);
		return sb.toString();
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		if (arg0 instanceof Horloge) {
			Horloge h = (Horloge) arg0;
			if (h.getactualTime().equals(duration.getBegin())) {
				setPositionXY(positionX, positionY);
				Thread t = new Thread(this);
				t.start();

			}

		}

	}

	/**
	 * @return the duration
	 */
	public Duration getDuration() {
		return duration;
	}
}
